package com.rc.evcharger.netty.server;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Netty服务端启动代码
 */
public class NettyServer {
    static Logger logger = LoggerFactory.getLogger(NettyServer.class);

    private int port; //端口
    private final int hearBeat = 15;//心跳频率（秒）

    public NettyServer(int port) {
        super();
        this.port = port;
    }

    /**
     * 启动
     * @throws Exception
     */
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();//bossGroup 用于接受客户端连接的线程工作组
        EventLoopGroup workerGroup = new NioEventLoopGroup();//EventLoopGroup 是用来处理IO操作的多线程事件循环器(用于对接受客户端连接读写操作的线程工作组)
        logger.info("Netty Server ready to run on port:" + port + "......");
        try {
            // 配置服务器的NIO线程租
            //启动 NIO 服务的辅助启动类
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)//配置 Channel
                    //连接请求放在队列中等待处理
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //保持连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //注册handler
                    .childHandler(new ChildChannelHandler());

            // 绑定端口，同步等待成功
            ChannelFuture f = b.bind(port).sync();
            // 等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            // 优雅退出，释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    /**
     * 通道初始化器ChannelInitializer
     */
    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel sc) throws Exception {
            logger.info("server initChannel..");
            /**
             * （1） maxFrameLength - 发送的数据包最大长度；
             *
             * （2） lengthFieldOffset - 长度域偏移量，指的是长度域位于整个数据包字节数组中的下标；
             *
             * （3） lengthFieldLength - 长度域的自己的字节数长度。
             *
             * （4） lengthAdjustment – 长度域的偏移量矫正。 如果长度域的值，除了包含有效数据域的长度外，还包含了其他域（如长度域自身）长度，那么，就需要进行矫正。矫正的值为：包长 - 长度域的值 – 长度域偏移 – 长度域长。
             *
             * （5） initialBytesToStrip – 丢弃的起始字节数。丢弃处于有效数据前面的字节数量。比如前面有4个节点的长度域，则它的值为4。
             *
             * 公式: 发送数据包长度 = 长度域的值 + lengthFieldOffset + lengthFieldLength + lengthAdjustment
             *
             *   *********长度域低位在前、高位在后，采用小端模式************   不能打开/晶福源桩无法连接。
             */
            //sc.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 11, 2, 2, 0, false));

            //配置心跳处理器
            sc.pipeline().addLast(new IdleStateHandler(2 * hearBeat, 0, 0));
            //处理数据(业务逻辑)处理器
            sc.pipeline().addLast(new NettyServerHandler());
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 9889;
        if (args != null && args.length > 0) {
            port = Integer.valueOf(args[0]);
        }
        new NettyServer(port).run();
    }
}